package com.example.demo.common;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.SilentCssErrorHandler;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.DomElement;
import com.gargoylesoftware.htmlunit.html.DomNodeList;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlPage;

import java.util.List;

public class Reptile {
    private final WebClient webClient;
    private HtmlPage page = null;
    private int count;
    private int interval;
    private boolean isReset;

    public Reptile() {
        this.count = 10;
        this.interval = 500;
        this.isReset = false;

        this.webClient = new WebClient(BrowserVersion.CHROME);
        this.webClient.getOptions().setJavaScriptEnabled(true);
        this.webClient.getOptions().setCssEnabled(false);
        this.webClient.getOptions().setUseInsecureSSL(true);
        this.webClient.getOptions().setThrowExceptionOnScriptError(false);
        this.webClient.getOptions().setRedirectEnabled(true);
        this.webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
        this.webClient.getOptions().setTimeout(10000);
        this.webClient.setAjaxController(new NicelyResynchronizingAjaxController());
        this.webClient.setCssErrorHandler(new SilentCssErrorHandler());
        this.webClient.getCookieManager().setCookiesEnabled(true);
    }

    protected void finalize() {
        if (this.webClient != null) {
            this.webClient.close();
        }
    }

    public String open(String url) {
        try {
            this.page = this.webClient.getPage(url);
        }
        catch (Exception ex) {
            return "error";
        }

        return "success";
    }

    public void close() {
        if (this.webClient != null) {
            this.webClient.close();
        }
    }

    public void wait(int interval) {
        this.webClient.waitForBackgroundJavaScript(interval);
    }

    public void setPage(HtmlPage page) {
        this.page = page;
    }

    public void setCount(int count) {
        this.count = count;
        this.isReset = true;
    }

    public void setInterval(int interval) {
        this.interval = interval;
        this.isReset = true;
    }

    public void reset() {
        this.count = 10;
        this.interval = 500;
        this.isReset = false;
    }

    public DomElement getDomById(String id) {
        DomElement element;

        for (int i = 0; i < this.count; i++) {
            try {
                element = this.page.getElementById(id);
                if (element != null) {
                    return element;
                }
            }
            catch (Exception ignored) { }

            this.wait(this.interval);
        }

        if (this.isReset) {
            this.reset();
        }

        return null;
    }

    public DomElement getDomById(HtmlPage page, String id) {
        DomElement element;

        for (int i = 0; i < this.count; i++) {
            try {
                element = page.getElementById(id);
                if (element != null) {
                    return element;
                }
            }
            catch (Exception ignored) { }

            this.wait(this.interval);
        }

        if (this.isReset) {
            this.reset();
        }

        return null;
    }

    public DomElement getDomByName(String name) {
        DomElement element;

        for (int i = 0; i < this.count; i++) {
            try {
                element = this.page.getElementByName(name);
                if (element != null) {
                    return element;
                }
            }
            catch (Exception ignored) { }

            this.wait(this.interval);
        }

        if (this.isReset) {
            this.reset();
        }

        return null;
    }

    public DomElement getDomByName(HtmlPage page, String name) {
        DomElement element;

        for (int i = 0; i < this.count; i++) {
            try {
                element = page.getElementByName(name);
                if (element != null) {
                    return element;
                }
            }
            catch (Exception ignored) { }

            this.wait(this.interval);
        }

        if (this.isReset) {
            this.reset();
        }

        return null;
    }

    public DomElement getDomByTag(String tagName) {
        DomElement element;

        for (int i = 0; i < this.count; i++) {
            try {
                element = this.page.getElementsByTagName(tagName).get(0);
                if (element != null) {
                    return element;
                }
            }
            catch (Exception ignored) { }

            this.wait(this.interval);
        }

        if (this.isReset) {
            this.reset();
        }

        return null;
    }

    public DomElement getDomByTag(HtmlPage page, String tagName) {
        DomElement element;

        for (int i = 0; i < this.count; i++) {
            try {
                element = page.getElementsByTagName(tagName).get(0);
                if (element != null) {
                    return element;
                }
            }
            catch (Exception ignored) { }

            this.wait(this.interval);
        }

        if (this.isReset) {
            this.reset();
        }

        return null;
    }

    public DomElement getDomByTag(DomElement parent, String tagName) {
        DomElement element;

        for (int i = 0; i < this.count; i++) {
            try {
                element = parent.getElementsByTagName(tagName).get(0);
                if (element != null) {
                    return element;
                }
            }
            catch (Exception ignored) { }

            this.wait(this.interval);
        }

        if (this.isReset) {
            this.reset();
        }

        return null;
    }

    public DomElement getDomByTag(DomElement dom, String[] tagList) {
        int index = -1;

        for (int i = 0; i < tagList.length; i++) {
            if (tagList[i].contains(",")) {
                index = Integer.parseInt(tagList[i].split(",")[1]);
                dom = this.getDomListByTag(dom, tagList[i].split(",")[0]).get(index);
            }
            else {
                dom = this.getDomByTag(dom, tagList[i]);
            }
        }

        return index < 0 ? null : dom;
    }

    public DomElement getDomByXPath(String xPath) {
        DomElement element;

        for (int i = 0; i < this.count; i++) {
            try {
                element = this.page.getFirstByXPath(xPath);
                if (element != null) {
                    return element;
                }
            }
            catch (Exception ignored) { }

            this.wait(this.interval);
        }

        if (this.isReset) {
            this.reset();
        }

        return null;
    }

    public DomElement getDomByXPath(HtmlPage page, String xPath) {
        DomElement element;

        for (int i = 0; i < this.count; i++) {
            try {
                element = page.getFirstByXPath(xPath);
                if (element != null) {
                    return element;
                }
            }
            catch (Exception ignored) { }

            this.wait(this.interval);
        }

        if (this.isReset) {
            this.reset();
        }

        return null;
    }

    public List<DomElement> getDomListByName(String name) {
        List<DomElement> list;

        for (int i = 0; i < this.count; i++) {
            try {
                list = this.page.getElementsByName(name);
                if (list != null) {
                    return list;
                }
            }
            catch (Exception ignored) { }

            this.wait(this.interval);
        }

        if (this.isReset) {
            this.reset();
        }

        return null;
    }

    public List<DomElement> getDomListByName(HtmlPage page, String name) {
        List<DomElement> list;

        for (int i = 0; i < this.count; i++) {
            try {
                list = page.getElementsByName(name);
                if (list != null) {
                    return list;
                }
            }
            catch (Exception ignored) { }

            this.wait(this.interval);
        }

        if (this.isReset) {
            this.reset();
        }

        return null;
    }

    public DomNodeList<DomElement> getDomListByTag(String tagName) {
        DomNodeList<DomElement> list;

        for (int i = 0; i < this.count; i++) {
            try {
                list = this.page.getElementsByTagName(tagName);
                if (list != null) {
                    return list;
                }
            }
            catch (Exception ignored) { }

            this.wait(this.interval);
        }

        if (this.isReset) {
            this.reset();
        }

        return null;
    }

    public DomNodeList<HtmlElement> getDomListByTag(DomElement parent, String tagName) {
        DomNodeList<HtmlElement> list;

        for (int i = 0; i < this.count; i++) {
            try {
                list = parent.getElementsByTagName(tagName);
                if (list != null) {
                    return list;
                }
            }
            catch (Exception ignored) { }

            this.wait(this.interval);
        }

        if (this.isReset) {
            this.reset();
        }

        return null;
    }

    public List<DomElement> getDomListByXPath(String xPath) {
        List<DomElement> list;

        for (int i = 0; i < this.count; i++) {
            try {
                list = this.page.getByXPath(xPath);
                if (list != null) {
                    return list;
                }
            }
            catch (Exception ignored) { }

            this.wait(this.interval);
        }

        if (this.isReset) {
            this.reset();
        }

        return null;
    }

    public List<DomElement> getDomListByXPath(HtmlPage page, String xPath) {
        List<DomElement> list;

        for (int i = 0; i < this.count; i++) {
            try {
                list = page.getByXPath(xPath);
                if (list != null) {
                    return list;
                }
            }
            catch (Exception ignored) { }

            this.wait(this.interval);
        }

        if (this.isReset) {
            this.reset();
        }

        return null;
    }

    public boolean isHtmlContains(DomElement dom, String content) {
        return dom != null && dom.asXml().contains(content);
    }

    public boolean isTextContains(DomElement dom, String content) {
        return dom != null && dom.getTextContent().contains(content);
    }

    public String getHtml(DomElement dom) {
        String content = "";
        try {
            content = dom.asXml();
        }
        catch (Exception ignored) { }

        return content;
    }

    public String getText(DomElement dom) {
        String content = "";
        try {
            content = dom.getTextContent();
        }
        catch (Exception ignored) { }

        return content;
    }

    public String getPageUrl(HtmlPage page) {
        return page.getUrl().toString();
    }
}
